/*
 * Menu.java  0.4.0 / Oct 26, 2010
 *
 * Copyright (c) 2010 - 2011, cute4j.com and contributors.
 *
 * This software is licensed under the LGPL version 2.1 license.
 * A copy of this license is included in the file LICENSE-LGPL.txt.
 */
package com.cute4j.swing;

import com.cute4j.swing.layouts.LayoutManager;
import com.cute4j.swing.properties.MenuProperties;

/**
 * Menu Component.
 *
 * @cute4j.native
 *    generate="header"
 *
 * @author Slobodan Vrkacevic
 * @version 0.4.0
 */
public class Menu extends Container implements MenuProperties {

  // TODO: add Action (on action)

// Private Fields. -------------------------------------------------------------

  private String text;
  private int mnemonic;
  private final boolean autoExclusive;

// Public Constructors. --------------------------------------------------------

  /**
   * Constructs new Menu object.
   */
  public Menu() {
    this(null, true);
  }

  /**
   * Constructs new Menu object.
   *
   * @param text the text for the menu label
   */
  public Menu(String text) {
    this(text, true);
  }

  /**
   * Constructs new Menu object.
   *
   * @param text the text for the menu label
   * @param autoExclusive <tt>true</tt> if auto exclusive
   */
  public Menu(String text, boolean autoExclusive) {
    super(null);
    if (text == null) {
      mnemonic = -1;
    } else {
      this.text = text;
      mnemonic = SwingUtilities.getMnemonicIndex(text);
      _setText(_delegate, text); // NOPMD
    }
    this.autoExclusive = autoExclusive;
  }

// Public Methods. -------------------------------------------------------------

  /**
   * Returns text.
   *
   * @return text
   */
  public String getText() {
    return text;
  }

  /**
   * Sets text. Char '&' is keyboard mnemonic.
   *
   * @param text the text
   */
  public void setText(String text) {
    String oldText = this.text;
    if (oldText == null) {
      if (text == null) {
        return;
      }
    } else {
      if (oldText.equals(text)) {
        return;
      }
    }
    disposedCheck();
    _setText(_delegate, text);
    this.text = text;
    mnemonic = -1;
    firePropertyChange(PROPERTY_TEXT, oldText, text);
  }

  /**
   * Returns <tt>true</tt> if the keyboard mnemonic has been explicitly set.
   *
   * @return <tt>true</tt> if the keyboard mnemonic has been explicitly set
   */
  public boolean isMnemonicSet() {
    return (mnemonic >= 0);
  }

  /**
   * Returns the keyboard mnemonic.
   *
   * @return the keyboard mnemonic
   */
  public int getMnemonic() {
    return mnemonic;
  }

  /**
   * Sets the keyboard mnemonic.
   *
   * @param mnemonic the keyboard mnemonic
   */
  public void setMnemonic(int mnemonic) {
    int oldMnemonic = this.mnemonic;
    if (oldMnemonic != mnemonic) {
      if (mnemonic == -1) {
        if (text != null) {
          _setText(_delegate, text);
        }
      } else {
        if ((text != null) && (text.length() > mnemonic)) {
          StringBuffer sb = new StringBuffer(text);
          sb.insert(mnemonic, '&');
          _setText(_delegate, sb.toString());
        }
      }
      this.mnemonic = mnemonic;
      firePropertyChange(PROPERTY_MNEMONIC, oldMnemonic, mnemonic);
    }
  }

  /**
   * Adds menu item.
   *
   * @param menuItem the menu item
   *
   * @return the menu item argument
   */
  public MenuItem add(MenuItem menuItem) {
    super.add(menuItem);
    return menuItem;
  }

  /**
   * Adds menu item.
   *
   * @param menuItem the menu item
   * @param index the menu index
   *
   * @return the menu item argument
   */
  public MenuItem add(MenuItem menuItem, int index) {
    super.add(menuItem, index);
    return menuItem;
  }

  /**
   * Adds check box menu item.
   *
   * @param menuItem the check box menu item
   *
   * @return the check box menu item argument
   */
  public CheckBoxMenuItem add(CheckBoxMenuItem menuItem) {
    super.add(menuItem);
    return menuItem;
  }

  /**
   * Adds check box menu item.
   *
   * @param menuItem the check box menu item
   * @param index the check box menu index
   *
   * @return the check box menu item argument
   */
  public CheckBoxMenuItem add(CheckBoxMenuItem menuItem, int index) {
    super.add(menuItem, index);
    return menuItem;
  }

  /**
   * Adds radio button menu item.
   *
   * @param menuItem the radio button menu item
   *
   * @return the menu radio button item argument
   */
  public RadioButtonMenuItem add(RadioButtonMenuItem menuItem) {
    return add(menuItem, -1);
  }

  /**
   * Adds radio button menu item.
   *
   * @param menuItem the radio button menu item
   * @param index the radio button menu index
   *
   * @return the radio button menu item argument
   */
  public RadioButtonMenuItem add(RadioButtonMenuItem menuItem,
                                   int index) { // NOPMD
    super.add(menuItem, index);
    if (autoExclusive) {
      if (index < 0) {
        index = componentCount - 1;
      }
      if (index > 0) {
        Component beforeComponent = components[index - 1];
        if (beforeComponent instanceof RadioButtonMenuItem) {
          RadioButtonMenuItem beforeRadioButton =
                                        (RadioButtonMenuItem)beforeComponent;
          SelectableGroup selectableGroup = beforeRadioButton.
                                                          getSelectableGroup();
          if (selectableGroup == null) {
            selectableGroup = new SelectableGroup();
            selectableGroup.add(beforeRadioButton);
          }
          selectableGroup.add(menuItem);
        }
      }
    }
    return menuItem;
  }

  /**
   * Adds menu.
   *
   * @param menu the menu
   *
   * @return the menu argument
   */
  public Menu add(Menu menu) {
    super.add(menu);
    return menu;
  }

  /**
   * Adds menu.
   *
   * @param menu the menu
   * @param index the menu index
   *
   * @return the menu argument
   */
  public Menu add(Menu menu, int index) {
    super.add(menu, index);
    return menu;
  }

  /**
   * Adds separator.
   *
   * @return separator
   */
  public Separator addSeparator() {
    Separator separator = new Separator();
    add(separator);
    return separator;
  }

  /**
   * Adds separator.
   *
   * @param index the separator index
   *
   * @return separator
   */
  public Separator addSeparator(int index) {
    Separator separator = new Separator();
    add(separator, index);
    return separator;
  }

  /**
   * Adds separator.
   *
   * @param text the text
   *
   * @return separator
   */
  public Separator addSeparator(String text) {
    Separator separator = new Separator(text);
    add(separator);
    return separator;
  }

  /**
   * Adds separator.
   *
   * @param text the text
   * @param index the separator index
   *
   * @return separator
   */
  public Separator addSeparator(String text, int index) {
    Separator separator = new Separator(text);
    add(separator, index);
    return separator;
  }

  /**
   * Displays popup menu at specified location.
   *
   * @param x the x coordinate of the location
   * @param y the y coordinate of the location
   */
  public void show(int x, int y) {
    disposedCheck();
    _show(_delegate, x, y);
  }

// Overridden Methods. ---------------------------------------------------------

  /**
   * {@inheritDoc}
   */
  public void setLayout(LayoutManager layoutManager) {
    // empty method
  }

  /**
   * {@inheritDoc}
   */
  public void validate() {
    // empty method
  }

  /**
   * {@inheritDoc}
   */
  public void invalidate() {
    // empty method
  }

  /**
   * {@inheritDoc}
   */
  public void revalidate() {
    // empty method
  }

  /**
   * {@inheritDoc}
   */
  public void updateLocalization() {
    super.updateLocalization();
    if (text != null) {
      _setText(_delegate, localizeString(text));
    }
  }

  /**
   * {@inheritDoc}
   */
  protected String paramString() {
    StringBuffer sb = new StringBuffer(super.paramString());
    if (text != null) {
      sb.append(",text=");
      sb.append(text);
    }
    return sb.toString();
  }

  void releaseChild(Component child) {
    if (child instanceof RadioButtonMenuItem) {
      RadioButtonMenuItem radioButtonItem = (RadioButtonMenuItem)child;
      SelectableGroup selectableGroup = radioButtonItem.getSelectableGroup();
      if (selectableGroup != null) {
        selectableGroup.remove(radioButtonItem);
      }
    }
    super.releaseChild(child);
  }

// Package-Private Native Methods. ---------------------------------------------

  native long _create();

  native void _setText(long delegate, String text);

  native void _insertChild(long delegate, long childDelegate, int index);

  native void _removeChild(long delegate, long childDelegate);

  native void _show(long delegate, int x, int y);

}
